package core

import (
	//"fmt"
	"goetl/models"
	"goetl/services"

	"github.com/emirpasic/gods/lists/arraylist"
)

//流程运行时线程
type FlowRuntime struct {
	stepRuntimes map[string]*StepRuntime
	//运行ID
	executionId string
	//人员ID
	userId string

	deployment AgentProjectVersionFlowDeployment
	agent      models.Agent

	ManipulateFlow models.Flow
}

func NewFlowRuntime(executionId string, userId string, deployment AgentProjectVersionFlowDeployment, agent models.Agent) *FlowRuntime {

	stepRuntimes := make(map[string]*StepRuntime)
	flowRuntime := &FlowRuntime{executionId: executionId, userId: userId, deployment: deployment, stepRuntimes: stepRuntimes}
	flowRuntime.initFlowRuntime()

	return flowRuntime
}

func (this *FlowRuntime) Execute() {

	this.start()
}
func (this *FlowRuntime) initFlowRuntime() {

	this.ManipulateFlow = this.manipulateFlow(this.deployment.flow)

	links := this.ManipulateFlow.FlowStepLinks

	for i := range this.ManipulateFlow.FlowSteps {
		flowStep := this.ManipulateFlow.FlowSteps[i]

		enabled := flowStep.ComponentId.GetBoolean("enabled", true)
		if enabled {
			flowParameters := make(map[string]string) //?

			context := NewComponentContext(this.deployment.deployment, this.ManipulateFlow, flowStep, flowParameters)

			stepRuntime := NewStepRuntime(*context, this)

			this.stepRuntimes[flowStep.Id] = stepRuntime
		}
	}

	for stepId, stepRuntime := range this.stepRuntimes {
		targetStepRuntimes := arraylist.New()
		sourceStepRuntimes := arraylist.New()
		for i := range links {
			flowStepLink := links[i]

			if stepId == flowStepLink.SourceStepId {
				runtime := this.stepRuntimes[flowStepLink.TargetStepId]
				if runtime != nil {
					targetStepRuntimes.Add(runtime)
				}
			}
			if stepId == flowStepLink.TargetStepId {
				runtime := this.stepRuntimes[flowStepLink.SourceStepId]
				if runtime != nil {
					sourceStepRuntimes.Add(runtime)
				}
			}
		}
		stepRuntime.TargetStepRuntimes = targetStepRuntimes
		stepRuntime.SetSourceStepRuntimes(sourceStepRuntimes)
	}

}
func (this *FlowRuntime) start() {
	startSteps := this.findStartSteps()

	for _, stepRuntime := range this.stepRuntimes {
		stepRuntime.Start()
	}

	for _, stepRuntime := range this.stepRuntimes {
		stepRuntime.StartRunning()

		go stepRuntime.Run()
	}
	startSteps.Each(func(i int, s interface{}) {
		stepRuntime := *(s.(*StepRuntime))
		stepRuntime.Queue(&Message{Type: "ControlMessage"})
	})

}

func (this *FlowRuntime) manipulateFlow(flow models.Flow) models.Flow {
	clone := flow
	for i := range clone.FlowSteps {
		flowStep := clone.FlowSteps[i]
		_, c := services.ConfigurationService.FindComponent(flowStep.ComponentId.Id, true)
		flowStep.ComponentId = &c
	}
	_, clone.FlowStepLinks = services.ConfigurationService.FindFlowStepLinks(flow.Id)
	return clone
}

func (this *FlowRuntime) findStartSteps() *arraylist.List {

	starterSteps := arraylist.New()

	for stepId, stepRuntime := range this.stepRuntimes {
		links := this.ManipulateFlow.FlowStepLinks
		isTargetStep := false
		for i := range links {
			flowStepLink := links[i]

			if _, ok := this.stepRuntimes[flowStepLink.SourceStepId]; ok && stepId == flowStepLink.TargetStepId {
				isTargetStep = true
			}
		}
		if !isTargetStep {
			stepRuntime.context.StartStep = true
			starterSteps.Add(stepRuntime)
		}
	}
	return starterSteps
}
